package com.tgjorgoski.sidekicknotes.browser;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.*;
import java.util.List;

import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

import com.tgjorgoski.sidekicknotes.filedata.FileInformation;
import com.tgjorgoski.sidekicknotes.rtfview.support.SpellCheckSupport;
import com.tgjorgoski.utils.IconResource;
import com.tgjorgoski.utils.VerticalGridLayout;
import com.tgjorgoski.utils.ViewUtils;
import com.tgjorgoski.window.Session;

public class BrowserSubPanel extends JPanel implements AbstractFileBrowserPanel, Accessible, MouseListener, FocusListener {
    static String UP_ACTION = "UP_ACTION";
    static String DOWN_ACTION = "DOWN_ACTION";
    static String LEFT_ACTION = "LEFT_ACTION";
    static String RIGHT_ACTION = "RIGHT_ACTION";
	
	JLabel defaultLabel;
	VerticalGridLayout theBrowserLayout;
	int colWidth, rowHeight;
	private static final int HOR_GAP=5, VER_GAP=0;
	Color selectionColorBG = new Color(0,0,150);
	Color selectionColorFG = new Color(255,255,255);
	
	Comparator<File> activeComparator = new Comparator<File>(){
		public int compare(File o1, File o2) {
			return o1.getName().compareToIgnoreCase(o2.getName());
		}
	};
	
	List<JLabel> selectedLabels = new ArrayList<JLabel>();
	Font browserFont = new Font("Tahoma",Font.PLAIN, 14);

	JRadioButtonMenuItem spellcheckDefault, spellcheckOn, spellcheckOff;
	JMenu spellcheckSubmenu;
	ButtonGroup bg;
	JMenuItem deleteMenuItem, renameMenuItem;
	
	private File lastSelectedFile;
	
	public BrowserSubPanel() {
		setLayout(null);

		bg = new ButtonGroup();
		spellcheckOn = new JRadioButtonMenuItem("Spellcheck On");
		spellcheckOff = new JRadioButtonMenuItem("Spellcheck Off");
		spellcheckDefault = new JRadioButtonMenuItem("Use Default");
		bg.add(spellcheckOn);
		bg.add(spellcheckOff);
		bg.add(spellcheckDefault);
		spellcheckSubmenu=new JMenu("Spellcheck");
		spellcheckSubmenu.add(spellcheckOn);
		spellcheckSubmenu.add(spellcheckOff);
		spellcheckSubmenu.addSeparator();
		spellcheckSubmenu.add(spellcheckDefault);
		
		deleteMenuItem = new JMenuItem("Delete");
		deleteMenuItem.setIcon(IconResource.getIconResource("delete"));
		renameMenuItem = new JMenuItem("Rename");
		renameMenuItem.setIcon(IconResource.getIconResource("rename"));
		//show the right click menu
		renameMenuItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Session.getHTMLView().rename(lastSelectedFile);
			}
		});
		deleteMenuItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Session.getHTMLView().delete(lastSelectedFile);
			}
		});


		defaultLabel= new JLabel();
		defaultLabel.setIcon(IconResource.getIconResource("writer"));
		Dimension dim = defaultLabel.getPreferredSize();
		rowHeight=dim.height;
		colWidth=200;		

		//Install Kumar's search
        ActionMap actionMap = getActionMap();
        Action findAction = new BrowserFindAction(true);
        String name = (String)findAction.getValue(Action.NAME);
        actionMap.put(name, findAction);
        InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_L, Event.CTRL_MASK);
        inputMap.put(key, name);
        
        //install moving through files actions
        inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        addDirectionAction(KeyEvent.VK_DOWN, DOWN_ACTION, actionMap, inputMap);
        addDirectionAction(KeyEvent.VK_UP, UP_ACTION, actionMap, inputMap);
        addDirectionAction(KeyEvent.VK_LEFT, LEFT_ACTION, actionMap, inputMap);
        addDirectionAction(KeyEvent.VK_RIGHT, RIGHT_ACTION, actionMap, inputMap);

		setFocusable(true);

		addMouseListener(this);
		
		setFocusCycleRoot(true);
	}
	
	private void addDirectionAction(final int keyEvent, String name, ActionMap actionMap, InputMap inputMap) {
        KeyStroke keyCode = KeyStroke.getKeyStroke(keyEvent, 0);
        Action upAction = new AbstractAction(name) {
			public void actionPerformed(ActionEvent e) {
				goToNextPlace(keyEvent);
			}
		};
        actionMap.put(name, upAction);
        inputMap.put(keyCode, name);
	}
	
	public void setFileList(List<File> files, List<String> snippets) {
		removeAll();
		
		Collections.sort(files);
		int i=0;
		
		for (File theFile : files) {
			String snippet=null;
			if(snippets!=null) {
				snippet = snippets.get(i);
			}
			i++;
			FileLabel newLabel = new FileLabel(theFile, snippet);
			//newLabel.setIcon(fsv.getSystemIcon(theFile));
			newLabel.setIcon(IconResource.getIconResource("writer"));
			newLabel.setIconTextGap(4);
			newLabel.setBorder(new EmptyBorder(0,0,0,3));
			newLabel.setFocusable(true);
			newLabel.setFont(browserFont);
			newLabel.addMouseListener(this);
			newLabel.addFocusListener(this);
			add(newLabel);
		}	
		
		refreshView();
	}
	
	protected List<FileLabel> getFileLabels() {
		List<FileLabel> fileLabels = new ArrayList<FileLabel>();
		int numOfFiles = getComponentCount();
		for (int i = 0; i < numOfFiles; i++) {
			Component cI = getComponent(i);
			if (cI instanceof FileLabel) {
				fileLabels.add((FileLabel)cI);
			}
		}
		return fileLabels;
	}

	public void refreshView() {
		int numOfFiles = getComponentCount();
		
		if (numOfFiles==0) {
			return;
		}
		
		int fullHeight = getHeight();
		int howMuchPerColumn = (int)((1.0*fullHeight)/(rowHeight+VER_GAP));
		int numberOfColumns = (int)((1.0*numOfFiles)/howMuchPerColumn)+1;
		setLayout(new VerticalGridLayout(howMuchPerColumn,numberOfColumns,HOR_GAP,VER_GAP,rowHeight,colWidth));
		invalidate();
		
		Component cp = getParent();
		if (cp instanceof JViewport) {
			JViewport jvp = (JViewport)cp;
			jvp.validate();
			jvp.repaint();
		}
	}
	
	private JPopupMenu spellCheckOptionsMenu = new JPopupMenu();

	public void mouseClicked(MouseEvent e) {
		Component comp = e.getComponent();
		if (comp instanceof FileLabel) {
			final FileLabel fl = (FileLabel)comp;
			if (e.getClickCount()==2 && e.getButton()==MouseEvent.BUTTON1) {
				File file = fl.getFile();
				Session.getHTMLView().requestFileOpen(file);
			} else if (SwingUtilities.isRightMouseButton(e)) {
				lastSelectedFile=fl.getFile();
				Action refreshAction = new AbstractAction("Refresh") {
					public void actionPerformed(ActionEvent e) {
						Session.getHTMLView().refresh(null);
					}
				};
				
				ActionListener al = new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						int optionSet=FileInformation.SPELLCHECK_DEFAULT;
						if (spellcheckOn.isSelected()) {
							optionSet = FileInformation.SPELLCHECK_USE;
						} else if (spellcheckOff.isSelected()) {
							optionSet = FileInformation.SPELLCHECK_DONT_USE;
						}
						fl.getFileInformation().setUseSpellCheck(optionSet);
						Session.getHTMLEditor().updateSpellcheckState();
					}
				};
				spellcheckOn.addActionListener(al);
				spellcheckOff.addActionListener(al);
				spellcheckDefault.addActionListener(al);
				
				JPopupMenu fileContextMenu = ViewUtils.createAndTrackPopupMenu();
				fileContextMenu.add(renameMenuItem);
				fileContextMenu.addSeparator();
				fileContextMenu.add(spellcheckSubmenu);
				fileContextMenu.addSeparator();
				fileContextMenu.add(deleteMenuItem);
				//fileContextMenu.addSeparator();
				//fileContextMenu.add(refreshAction);
				
				int useSpellcheck = fl.getFileInformation().getUseSpellCheck();
				if (useSpellcheck==FileInformation.SPELLCHECK_USE) {
					spellcheckOn.setSelected(true);
				} else if (useSpellcheck==FileInformation.SPELLCHECK_DONT_USE) {
					spellcheckOff.setSelected(true);
				} else {
					spellcheckDefault.setSelected(true);
				}
 
				fileContextMenu.show(e.getComponent(), e.getX(), e.getY());
			}
			//TODO:Implement Right-Click actions too
		} else {
			requestFocusInWindow();
		}
	}
	public void mouseEntered(MouseEvent e) {
	}
	public void mouseExited(MouseEvent e) {
	}
	public void mousePressed(MouseEvent e) {
	}
	public void mouseReleased(MouseEvent e) {
	}

	protected FileLabel getLeadSelection() {
		if (selectedFiles.size()==0) return null;
		return selectedFiles.get(0);
	}
	
	public boolean focusOnFile(File file) {
		List<FileLabel> labels = getFileLabels();
		FileLabel likeThis = new FileLabel(file);
		int index = labels.indexOf(likeThis);
		if (index==-1) return false;
		selectionChange(true, labels.get(index), false);
		return true;
	}
	
	public void focusGained(FocusEvent e) {
		Component comp = e.getComponent();
		if (comp instanceof FileLabel) {
			selectionChange(true, (FileLabel)comp, true);
		}
	}
	
	public void focusLost(FocusEvent e) {
	}
	
	private List<FileLabel> selectedFiles= new ArrayList<FileLabel>();
	protected void selectionChange(boolean replace, FileLabel selected, boolean requestFocusInWindow) {
		//HACK:When a label was focused, and the Kumar's search was activated
		//for some reason on arrow-up and arrow-down, the focusGained() is called
		//which in turn calls this method, and the selection couldn't change
		if (requestFocusInWindow)
			requestFocusInWindow();
		
		
		if (replace) {
			for (FileLabel selFile : selectedFiles) {
				selFile.setOpaque(false);
				selFile.setBackground(null);
				selFile.setForeground(null);
			}
			selectedFiles.clear();
		}
		if (selectedFiles.indexOf(selected)==-1) {
			selectedFiles.add(selected);
			selected.setOpaque(true);
			selected.setBackground(Color.BLUE);
			selected.setForeground(Color.WHITE);
			Collections.sort(selectedFiles, new Comparator<FileLabel>() {
				public int compare(FileLabel o1, FileLabel o2) {
					return activeComparator.compare(o1.getFile(), o2.getFile());
				}
			});
		}
		//find the row and column of the newly selected file, and 'move' the view to it
		int place = getFileLabels().indexOf(selected);
		if (place!=-1) {
			VerticalGridLayout vgl = (VerticalGridLayout)getLayout();
			int noRows = vgl.getRows();
			int atRow = place/noRows;
			int lRect = (vgl.getColWidth() + vgl.getHgap())*atRow;
			Component cp = getParent();
			if (cp instanceof JViewport) {
				JViewport jvp = (JViewport)cp;
				Point vPosition = jvp.getViewPosition();
				Rectangle rect = new Rectangle(lRect-vPosition.x, -vPosition.y, vgl.getColWidth(), vgl.getRowHeight());
				jvp.scrollRectToVisible(rect);
			}
		}
		
		invalidate();
		repaint();
	}
	
	protected void openSelectedFile() {
		if (selectedFiles.size()==1) {
			Session.getHTMLView().requestFileOpen(selectedFiles.get(0).getFile());
		}
	}
	
	public FileLabel goToNextPlace(int key) {
		int nextPlace = 0;
		FileLabel leadSelection = getLeadSelection();
		List<FileLabel> fileLabels = getFileLabels();
		
		//we don't have anything so don't bother
		if (fileLabels.size()==0) return null;
		
		if (leadSelection!=null) {
			//find the row and column of the newly selected file, and 'move' the view to it
			int place = getFileLabels().indexOf(leadSelection);
			VerticalGridLayout vgl = (VerticalGridLayout)getLayout();
			int noRows = vgl.getRows();
			int atRow = place%noRows;
			int noRowsAtLastColumn = fileLabels.size() - (fileLabels.size()/noRows)*noRows;
			if (place!=-1) {
				switch (key) {
				case KeyEvent.VK_DOWN:
					if (place<fileLabels.size()-1) {
						nextPlace=place+1;
					} else {
						nextPlace=0;
					}
					break;
				case KeyEvent.VK_UP:
					if (place>0) {
						nextPlace=place-1;
					} else {
						nextPlace=fileLabels.size()-1;
					}
					break;
				case KeyEvent.VK_RIGHT:
					nextPlace=place+noRows;
					if (nextPlace>=fileLabels.size()) {
						if (atRow<noRows-1) {
							nextPlace=atRow+1;
						} else {
							nextPlace=0;
						}
					}
					break;
				case KeyEvent.VK_LEFT:
					nextPlace=place-noRows;
					if (nextPlace<0) {
						nextPlace=fileLabels.size()-noRowsAtLastColumn+atRow-1;
						//find the last possible label on atRow-1 row
						if (noRowsAtLastColumn<=atRow-1) {
							nextPlace=nextPlace-noRows;
						}
					}
				default:
					break;
				}
			}
		}
		if (nextPlace<0) nextPlace=fileLabels.size()-1;
		if (nextPlace>=fileLabels.size()) nextPlace=0;
		
		FileLabel nextLabel = fileLabels.get(nextPlace);
		selectionChange(true, nextLabel, true);
		return nextLabel;
	}

	public void focusOnFirstFile() {
		FileLabel fl = goToNextPlace(KeyEvent.VK_DOWN);
		if (fl!=null) fl.requestFocusInWindow();
	}

	public boolean isVertical() {
		return false;
	}
	
	public JComponent getViewportView() {
		// TODO Auto-generated method stub
		return this;
	}

	public AccessibleContext getAccessibleContext() {
		// TODO Auto-generated method stub
		return null;
	}

	private BrowserPanel bPanel;
	public BrowserPanel getBrowserPanel() {
		return bPanel;
	}

	public void setBrowserPanel(BrowserPanel browserPanel) {
		this.bPanel=browserPanel;
	}
}
